package cn.melonlib.cores.graphql.config.bean.impl;

import cn.melonlib.cores.commons.model.entity.IEntity;
import cn.melonlib.cores.graphql.comp.GraphQLSchemaTools;
import cn.melonlib.cores.graphql.comp.config.WorkerParametersReader;
import cn.melonlib.cores.graphql.comp.service.GraphQLService;
import cn.melonlib.cores.graphql.config.bean.GraphQLQueryWorker;
import cn.melonlib.cores.graphql.model.bean.*;
import cn.melonlib.cores.jpa.model.bean.collections.EntityMap;
import cn.melonlib.cores.jpa.model.bean.impl.PaginationList;
import cn.melonlib.cores.model.anno.WorkerLargeData;
import cn.melonlib.cores.model.anno.WorkerQuery;
import graphql.schema.DataFetchingEnvironment;
import org.springframework.aop.support.AopUtils;
import org.springframework.context.support.ApplicationObjectSupport;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Component
public class DefaultGQLQueryWorker<DATA> extends ApplicationObjectSupport implements GraphQLQueryWorker<DATA> {

    @Resource
    private GraphQLService graphQLService;

    @Resource
    private WorkerParametersReader workerParametersReader;

    @Resource
    private GraphQLSchemaTools graphQLSchemaTools;

    public DATA query(DataFetchingEnvironment env, Method queryMethod, Object bean) throws Exception{
        WorkerQuery query= AnnotationUtils.findAnnotation(queryMethod, WorkerQuery.class);
        List<Object> params = workerParametersReader.getReader(String.class).readParams(Arrays.stream(queryMethod.getParameters())
                        .map(graphQLSchemaTools::getParameterName).collect(Collectors.toList())
                , queryMethod,env,graphQLService,bean);
        long start=System.currentTimeMillis();
        Object[] execParams=new Object[queryMethod.getParameterCount()];
        params.stream().reduce(0,(idx,param)->{
            execParams[idx]=param;
            return idx+1;
        },(idx,param)->null);
        Class<?> returnType=queryMethod.getReturnType();
        try {
            Object data = queryMethod.invoke(bean, execParams);
            long end = System.currentTimeMillis();
            logger.info("接口" + AopUtils.getTargetClass(bean).getName() + "#" + queryMethod.getName() + "完成时间：" + (end - start) + "ms");
            if (data instanceof PaginationList) {

                GraphQLPageInfo pageInfo = new GraphQLPageInfo((int) ((PaginationList<?>) data).getPage()
                        , (int) ((PaginationList<?>) data).getLimit(), ((PaginationList<?>) data).getOffset());
                if (((List<?>) data).isEmpty()) {
                    GraphQLConnection connection = new GraphQLConnection((List<?>) data, pageInfo, GraphQLResultInfo.create("查询成功", ((List<?>) data).size(), ""));
                    return (DATA) connection;
                }
                if (AnnotationUtils.findAnnotation(((List<?>) data).get(0).getClass(), WorkerLargeData.class) != null) {
                    GraphQLConnection connection = new GraphQLConnection(((PaginationList<?>) data).getData(), pageInfo, GraphQLResultInfo.create("查询成功", ((PaginationList<?>) data).getTotal(), ""));
                    return (DATA) connection;
                }
                List<EntityMap<Object, ? extends IEntity<? extends Serializable>>> transDatas = ((PaginationList<? extends IEntity<? extends Serializable>>) data).stream().map(EntityMap::new).collect(Collectors.toList());
                GraphQLConnection connection = new GraphQLConnection(transDatas, pageInfo, GraphQLResultInfo.create("查询成功", ((PaginationList<?>) data).getTotal(), ""));
                return (DATA) connection;
            } else if (data instanceof List) {
                Class<?> type = ResolvableType.forMethodReturnType(queryMethod).getGeneric(0).toClass();
                if (String.class.isAssignableFrom(type)) {
                    return (DATA) data;
                }

                GraphQLPageInfo pageInfo = new GraphQLPageInfo(0
                        , ((List<?>) data).size(), 0);

                if (((List<?>) data).isEmpty()) {
                    GraphQLConnection connection = new GraphQLConnection((List<Object>) data, pageInfo, GraphQLResultInfo.create("查询成功", ((List<?>) data).size(), ""));
                    return (DATA) connection;
                }
                if (AnnotationUtils.findAnnotation(((List<?>) data).get(0).getClass(), WorkerLargeData.class) != null) {
                    GraphQLConnection connection = new GraphQLConnection((List<Object>) data, pageInfo, GraphQLResultInfo.create("查询成功", ((List<?>) data).size(), ""));
                    return (DATA) connection;
                }
                if (((List<?>) data).get(0) instanceof IEntity) {
                    List<EntityMap<Object, ? extends IEntity<? extends Serializable>>> transDatas = ((List<? extends IEntity<? extends Serializable>>) data).stream().map(EntityMap::new).collect(Collectors.toList());
                    GraphQLConnection connection = new GraphQLConnection(transDatas, pageInfo, GraphQLResultInfo.create("查询成功", ((List<?>) data).size(), ""));
                    return (DATA) connection;
                } else {
                    GraphQLConnection connection = new GraphQLConnection((List<?>) data, pageInfo, GraphQLResultInfo.create("查询成功", ((List<?>) data).size(), ""));
                    return (DATA) connection;
                }
            } else if (data instanceof IEntity) {
                GraphQLEntityPackage entityPackage = GraphQLEntityPackage.create(new EntityMap<>((IEntity<? extends Serializable>) data), GraphQLResultInfo.create("查询成功", 1, ""));
                return (DATA) entityPackage;
            } else if (data == null) {
                GraphQLEntityPackage entityPackage = GraphQLEntityPackage.create(null, GraphQLResultInfo.create("查询成功", 0, ""));
                return (DATA) entityPackage;
            }
            else if (Objects.equals(Integer.class,returnType)||Objects.equals(Integer.TYPE,returnType)) {
                return (DATA) new GraphQLIntValue((Integer) data);
            }
            else if (Objects.equals(Long.class,returnType)||Objects.equals(Long.TYPE,returnType)) {
                return (DATA) new GraphQLLongValue((Long) data);
            }
            else if (Objects.equals(Boolean.class,returnType)||Objects.equals(Boolean.TYPE,returnType)) {
                return (DATA) new GraphQLBooleanValue((Boolean) data);
            }
            else if (Objects.equals(Boolean.class,returnType)||Objects.equals(Boolean.TYPE,returnType)) {
                return (DATA) new GraphQLBooleanValue((Boolean) data);
            }
            else if (Objects.equals(Double.class,returnType)||Objects.equals(Double.TYPE,returnType)) {
                return (DATA) new GraphQLDoubleValue((Double) data);
            }
            else if (Objects.equals(String.class,returnType)) {
                return (DATA) new GraphQLStringValue((String) data);
            }
            else {

            }
            return (DATA) data;
        }catch (InvocationTargetException exception){
            throw (Exception) exception.getTargetException();
        }finally {
            long end = System.currentTimeMillis();
            logger.info("接口" + AopUtils.getTargetClass(bean).getName() + "#" + queryMethod.getName() + "总执行时间：" + (end - start) + "ms");
        }
    }
}
